﻿using System;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using WeBlog.Interfaces;
using WeBlog.Models;
using WeBlog.Repositories;
using WeBlog.Resources;
using WeBlog.Services;

namespace WeBlog.Controllers {
	
	public class AccountController : ApplicationController
	{
		private readonly UserRepository _repository;	    
		private readonly IEmailService _emailService;

		public AccountController(IUnitOfWork unitOfWork, IEmailService emailService )
			: base( unitOfWork )
		{		    
			_repository = new UserRepository(unitOfWork);
			_emailService = emailService;
		}
		 
		[WeBlogAuthorize(Role.Admin), Theme("Admin")]
		public ActionResult Manage(GridSettings settings)
		{
			var model = new ManageAccountsViewModel(settings, UnitOfWork);
			return View(model);	
		}

		[Authorize]
		public ActionResult MyAccount()
		{
			var model = new MyAccountFormViewModel(CurrentUser);
			return View(model);
		}
		
		[Authorize]
		[HttpPost]
		public ActionResult MyAccount(FormCollection form)
		{
			var model = new MyAccountFormViewModel(CurrentUser);
			TryUpdateModel(model);

			bool changePassword = model.IsPasswordBeingChanged();
			if( changePassword ) ValidatePasswordFields(model);

			bool emailInUse = _repository.FindAll().Any( x => x.Email == model.Email && x.UserId != CurrentUser.UserId );
			if( emailInUse )
				ModelState.AddModelError("Email",Strings.Account_EmailAlreadyExists);

			if (ModelState.IsValid)
			{
				var user = _repository.Find(CurrentUser.UserId);
				user.FirstName = model.FirstName;
				user.LastName = model.LastName;
				user.Email = model.Email;

				if( changePassword ) 
					user.Password = model.NewPassword;

				Session["User"] = user;
				UnitOfWork.Commit();
				
				TempData.SetStatusMessage(Strings.Account_SavedSuccessfully);
				return RedirectToRoute("Default");
			}

			return View(model);
		}
		
		private void ValidatePasswordFields(MyAccountFormViewModel input)
		{
			if (input.IsPasswordBeingChanged() == false) return;

			if (CurrentUser.Validate(input.OldPassword) == false)
				ModelState.AddModelError("OldPassword", Strings.Account_InvalidPassword);

			if (input.NewPassword != input.ConfirmNewPassword)
				ModelState.AddModelError("NewPassword", Strings.Account_PasswordsDoNotMatch);

			if (!String.IsNullOrWhiteSpace(input.NewPassword))
			{
				if (input.NewPassword.Length < SiteConfiguration.MinPasswordLength)
					ModelState.AddModelError("NewPassword",
												String.Format(Strings.Account_PasswordMinLength,
															SiteConfiguration.MinPasswordLength));
			}
			else
			{
				ModelState.AddModelError("Password", Strings.Required);
			}
		}

		public ActionResult Profile(int id)
		{
			var model = new UserProfileModel(UnitOfWork, id);
			return View(model);
		}

		public ActionResult SignOut()
		{
			if (System.Web.HttpContext.Current != null)
			{
				FormsAuthentication.SignOut();
				System.Web.HttpContext.Current.Session.RemoveAll();
				System.Web.HttpContext.Current.Session.Abandon();
				System.Web.HttpContext.Current.User = null;                
			}
			else
			{
				Thread.CurrentPrincipal = null;
			}

			return RedirectToAction("Index", "Post");
		}

		public ActionResult Activate(int id)
		{
			User user = _repository.Find(id);
			if (user == null) return NotFound();
			user.Activated = true;
			UnitOfWork.Commit();
			_emailService.SendAccountActivatedMail(user);
			TempData.SetStatusMessage(Strings.Account_ActivationMessage);
			return RedirectToRoute("Default");
		}

		#region SignIn
		[WidgetBar(false)]
		public ActionResult SignIn()
		{
			return View();
		}

		[HttpPost]
		public ActionResult SignIn(LogOnModel logOn, string returnUrl = null)
		{
			if (ModelState.IsValid) {
				var user = _repository.FindByEmail(logOn.Email);
				if (user != null)
				{
					if (user.Validate(logOn.Password)) {                                                
						if (!user.Activated )
						{
							TempData.SetStatusMessage(Resources.Strings.Account_Pending);
							return View(logOn);
						}

						LogOn( user, logOn.RememberMe );

						if (string.IsNullOrWhiteSpace(returnUrl) || returnUrl == "/")
						{
							if( user.IsInRole(Role.Admin))
								return RedirectToAction("Index", "Admin");
							
							return RedirectToRoute("Default");
						}

						return Redirect(returnUrl);
					}
					ModelState.AddModelError("", Strings.Account_InvalidPassword);
				}
				else
					ModelState.AddModelError("", Strings.Account_InvalidUsername);
			}

			return View(logOn);
		}
		
		#endregion        		        

		#region Reset Password
		public ActionResult ResetPassword()
		{
			return View();
		}

		[HttpPost]
		public ActionResult ResetPassword(string email)
		{
			User user = _repository.FindByEmail(email);
			if (user == null)
			{
				ModelState.AddModelError("Email", Strings.Account_EmailUnknown);
				return View();
			}

			_emailService.SendResetPasswordMail(user, user.ResetPassword());
			UnitOfWork.Commit();
			TempData.SetStatusMessage(Strings.Account_ResetPasswordEmailSent);
			return RedirectToRoute("Default");
		}
		#endregion

		#region Register
		public ActionResult Register()
		{
			if( SiteConfiguration.AllowOpenRegistration == false )                            
				return NotFound();
			
			return View("Register");
		}

		[HttpPost]
		public ActionResult Register(RegisterModel register)
		{
			if (SiteConfiguration.AllowOpenRegistration == false)
				return NotFound();

			bool emailUsed = _repository.FindByEmail(register.Email) != null;
			if (emailUsed == true)
				ModelState.AddModelError("", Strings.Account_EmailAlreadyExists);

			if (!String.IsNullOrWhiteSpace(register.Password)) {
				if (register.Password != register.ConfirmPassword)
					ModelState.AddModelError("", Strings.Account_PasswordsDoNotMatch);

				if (register.Password.Length < SiteConfiguration.MinPasswordLength)
					ModelState.AddModelError("", String.Format(Strings.Account_PasswordMinLength, 5));
			}

			if (ModelState.IsValid) {
				var user = new User()
				{
					Email = register.Email,
					Password = register.Password,                    
					FirstName = register.FirstName,
					LastName = register.LastName,
					RoleFlag = RoleValues.Subscriber,
					Activated = false
				};
					
				_repository.Add(user);
				UnitOfWork.Commit();

				_emailService.SendRegistrationMail( user );
				TempData.SetStatusMessage(Strings.Account_Pending);
				return RedirectToRoute("Default");			
			}

			return View(register);
		}
		#endregion

		#region Edit
		[HttpPost, WeBlogAuthorize(Role.Admin), Theme("Admin")]
		public ActionResult Edit(int id, FormCollection notUsed )
		{
			var model = new EditUserFormViewModel(UnitOfWork, id);                        
			TryUpdateModel(model);

			if (ModelState.IsValid)
			{
				var user = _repository.Find(id);
				user.FirstName = model.FirstName;
				user.LastName = model.LastName;
				user.Email = model.Email;
				user.RoleFlag = model.RoleFlag;
				UnitOfWork.Commit();
				TempData.SetStatusMessage(Strings.Account_SavedSuccessfully);
				return RedirectToAction("Manage", "Account");
			}

			return View(model);
		}

		[WeBlogAuthorize(Role.Admin), Theme("Admin")]
		public ActionResult Edit(int id)
		{
			if (id == CurrentUser.UserId)
				return RedirectToAction("MyAccount");

			var model = new EditUserFormViewModel(UnitOfWork, id);            
			return View(model);
		}
		#endregion        

		#region Create
		[WeBlogAuthorize(Role.Admin), Theme("Admin")]
		public ActionResult Create()
		{
			var model = new CreateUserFormViewModel();
			return View( model );
		}

		[HttpPost, WeBlogAuthorize(Role.Admin), Theme("Admin")]
		public ActionResult Create(CreateUserFormViewModel input)
		{
			bool emailUsed = _repository.FindByEmail(input.Email) != null;
			if (emailUsed) ModelState.AddModelError("Email", Strings.Account_EmailAlreadyExists);

			if (ModelState.IsValid)
			{
				var user = new User();
				user.FirstName = input.FirstName;
				user.LastName = input.LastName;
				user.Email = input.Email;
				user.RoleFlag = input.RoleFlag;
				var password = user.ResetPassword();                

				_repository.Add(user);
				UnitOfWork.Commit();
				_emailService.SendAccountNotificationEmail(user, password);
				TempData.SetStatusMessage(Strings.Account_CredentialsSent);
				return RedirectToAction("Manage", "Account");                
			}

			return View(input);
		}        
		#endregion

		[HttpPost, Authorize]
		public virtual JsonResult Delete(int id)
		{
			try
			{
				User user = _repository.Find(id);
				_repository.Remove(user);
				UnitOfWork.Commit();
				return Json(new JsonResponse { Success = true });
			}
			catch (Exception ex)
			{
				return Json(new JsonResponse { Success = false, Message = ex.Message });
			}
		}
	}
}
